﻿using Xejen.Communication.Configuration;
using Xejen.Communication.Http.Abstract;
using Xejen.Communication.Http.Configuration;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace Xejen.Communication.Http
{
    /// <summary>
    /// 代表以<see langword="HttpClient"/>驱动方式向远程服务器发起请求
    /// </summary>
    /// <creator>marc</creator>
    internal class HttpClientInvoker : IHttpInvoker
    {
        /// <inheritdoc/>
        public HttpConfig Config { get; set; }

        ///// <summary>
        ///// 令牌
        ///// </summary>
        //public string Token { get; set; }

        /// <summary>
        /// 请求头
        /// </summary>
        public NameValueCollection Headers { get; set; }

        /// <inheritdoc cref="HttpClientInvoker"/>
        protected HttpClientInvoker() { }

        ///// <inheritdoc cref="HttpClientInvoker"/>
        //public HttpClientInvoker(HttpConfig config, string token = default, NameValueCollection headers = default)
        //{
        //    Check.NotNull(config, nameof(config));

        //    Config = config;

        //    Token = token;
        //    Headers = headers;
        //}

        /// <inheritdoc cref="HttpClientInvoker"/>
        public HttpClientInvoker(HttpConfig config, NameValueCollection headers)
        {
            Check.NotNull(config, nameof(config));

            Config = config;

            //Token = token;
            Headers = headers;
        }

        /// <inheritdoc/>
        public async Task<HttpResponse> GetAsync(string uri, int timeout, CancellationToken cancellationToken)
        {
            using (var handler = new HttpClientHandler())
            {
                if (!(string.IsNullOrEmpty(Config.UserName) && string.IsNullOrEmpty(Config.Password)))
                {
                    // 设置用户名和密码
                    handler.Credentials = new NetworkCredential(Config.UserName, Config.Password);
                }

                using (HttpClient httpClient = CreateHttpClient(handler, timeout))
                {
                    AddHeaderParameters(httpClient, Headers);

                    HttpResponseMessage response = await httpClient.GetAsync(uri, cancellationToken);

                    return await HandleResponseAsync(response);
                }
            }
        }

        /// <inheritdoc/>
        public async Task<HttpResponse> PostAsync(string uri, object data, int timeout, CancellationToken cancellationToken)
        {
            using (var handler = new HttpClientHandler())
            {
                if (!(string.IsNullOrEmpty(Config.UserName) && string.IsNullOrEmpty(Config.Password)))
                {
                    // 设置用户名和密码
                    handler.Credentials = new NetworkCredential(Config.UserName, Config.Password);
                }

                using (HttpClient httpClient = CreateHttpClient(handler, timeout))
                {
                    AddHeaderParameters(httpClient, Headers);

                    IHttpContentStrategy contentStrategy = GetContentStrategy();
                    HttpContent content = contentStrategy.CreateHttpContent(data);

                    using (content)
                    {
                        HttpResponseMessage response = await httpClient.PostAsync(uri, content, cancellationToken);

                        return await HandleResponseAsync(response);
                    }
                }
            }
        }

        ///// <inheritdoc/>
        //public async Task<HttpResponse> PostAsync(string uri, Stream stream, ContentDispositionHeaderValue disposition, int timeout , CancellationToken cancellationToken )
        //{
        //    using (HttpClient httpClient = CreateHttpClient(Token, timeout))
        //    {
        //        AddHeaderParameters(httpClient, Headers);

        //        HttpContent fileStreamContent = new StreamContent(stream);
        //        fileStreamContent.Headers.ContentDisposition = disposition;
        //        fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");

        //        IHttpContentStrategy contentStrategy = GetContentStrategy();
        //        var content = contentStrategy.CreateHttpContent(fileStreamContent);

        //        using (content)
        //        {
        //            var response = await httpClient.PostAsync(uri, content, cancellationToken);

        //            return await HandleResponseAsync(response);
        //        }
        //    }
        //}

        /// <inheritdoc/>
        public async Task<HttpResponse> PutAsync(string uri, object data, int timeout, CancellationToken cancellationToken)
        {
            using (var handler = new HttpClientHandler())
            {
                if (!(string.IsNullOrEmpty(Config.UserName) && string.IsNullOrEmpty(Config.Password)))
                {
                    // 设置用户名和密码
                    handler.Credentials = new NetworkCredential(Config.UserName, Config.Password);
                }

                using (HttpClient httpClient = CreateHttpClient(handler, timeout))
                {
                    AddHeaderParameters(httpClient, Headers);

                    IHttpContentStrategy contentStrategy = GetContentStrategy();
                    HttpContent content = contentStrategy.CreateHttpContent(data);

                    using (content)
                    {
                        HttpResponseMessage response = await httpClient.PutAsync(uri, content, cancellationToken);

                        return await HandleResponseAsync(response);
                    }
                }
            }
        }

        /// <inheritdoc/>
        public async Task<HttpResponse> DeleteAsync(string uri, int timeout, CancellationToken cancellationToken)
        {
            using (var handler = new HttpClientHandler())
            {
                if (!(string.IsNullOrEmpty(Config.UserName) && string.IsNullOrEmpty(Config.Password)))
                {
                    // 设置用户名和密码
                    handler.Credentials = new NetworkCredential(Config.UserName, Config.Password);
                }

                using (HttpClient httpClient = CreateHttpClient(handler, timeout))
                {
                    AddHeaderParameters(httpClient, Headers);

                    HttpResponseMessage response = await httpClient.DeleteAsync(uri, cancellationToken);

                    return await HandleResponseAsync(response);
                }
            }
        }

        /// <summary>
        /// 创建httpclient连接
        /// </summary>
        /// <param name="handler">处理器</param>
        /// <param name="token">登录令牌。因为令牌其实是放在Headers中的，所以，只要Headers中设置有请求头的令牌就可以了，关键字是Authorization</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        private HttpClient CreateHttpClient(HttpClientHandler handler, string token, int timeout)
        {
            var httpClient = new HttpClient(handler) { Timeout = new TimeSpan(0, 0, 0, 0, timeout) };

            //if (!string.IsNullOrEmpty(token))
            //{
            //    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
            //}
            //if (!(string.IsNullOrEmpty(Config.UserName) && string.IsNullOrEmpty(Config.Password)))
            //{
            //    string clientId = Config.UserName;
            //    string clientSecret = Config.Password;
            //    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}")));
            //}

            return httpClient;
        }

        /// <summary>
        /// 创建httpclient连接
        /// </summary>
        /// <param name="handler">登录令牌</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        private HttpClient CreateHttpClient(HttpClientHandler handler, int timeout)
        {
            var httpClient = new HttpClient(handler) { Timeout = new TimeSpan(0, 0, 0, 0, timeout) };

            return httpClient;
        }

        /// <summary>
        /// 添加请求头
        /// </summary>
        /// <param name="httpClient">请示客户端</param>
        /// <param name="parameters">请求头集合</param>
        private void AddHeaderParameters(HttpClient httpClient, NameValueCollection parameters)
        {
            if (httpClient == null)
                return;

            if (parameters == null)
                return;

            foreach (string key in parameters)
            {
                httpClient.DefaultRequestHeaders.Add(key, parameters[key]);
            }
        }

        /// <summary>
        /// 处理响应并抛出异常
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private async Task<HttpResponse> HandleResponseAsync(HttpResponseMessage response)
        {
            using (response)
            {
                string content = await response.Content.ReadAsStringAsync();

                if (!response.IsSuccessStatusCode)
                {
                    throw new HttpRequestException($"HTTP请求失败。状态码：{(int)response.StatusCode} ({response.ReasonPhrase})\n内容：{Environment.NewLine}{content}");
                }

                byte[] bytes = Config.Encoding.GetBytes(content);

                return HttpResponse.Success(bytes, encoding: Config.Encoding);
            }
        }

        /// <summary>
        /// 获取内容策略
        /// </summary>
        /// <returns></returns>
        private IHttpContentStrategy GetContentStrategy()
        {
            // 根据 HttpConfig.ContentType 返回相应的策略
            if (Config.ContentType == "application/json")
            {
                return new JsonContentStrategy(Config);
            }
            else if (Config.ContentType.StartsWith("application/x-www-form-urlencoded"))
            {
                return new FormUrlEncodedContentStrategy(Config);
            }
            else if (Config.ContentType.StartsWith("text/xml"))
            {
                return new TextXmlContentStrategy(Config);
            }
            else if (Config.ContentType.StartsWith("application/soap+xml"))
            {
                return new SoapXmlContentStrategy(Config);
            }
            // 如果有其他类型，可以继续添加相应的策略类

            throw new NotSupportedException($"不支持的 ContentType： {Config.ContentType}");
        }
    }
}
